using System;
using System.Collections.Generic;
using System.Text;

using RRHH.Competencias.DataAccessLayer.Generic;
using RRHH.Competencias.DataAccessLayer;
using RRHH.Competencias.Entities;
using RRHH.Competencias.Entities.AdminPermisos;
using RRHH.Competencias.BusinessLayer;

namespace RRHH.Competencias.Controladores
{
    /// <summary>
    /// Administra las operaciones relacionadas a permisos de usuario
    /// </summary>
    public class GestorPermiso
    {
        private IDALPermiso persistencia;

        public GestorPermiso()
        {
            persistencia = DALProvider.GetDALPermiso();    
        }

        /// <summary>
        /// Obtiene un listado de permisos 
        /// </summary>
        /// <param name="usuario">Usuario a buscar. Indicar null si no se desea incluir</param>
        /// <param name="funcion">Funcion a buscar. Indicar null si no se desea incluir</param>        
        /// <param name="soloActivos">True: Incluye registros que no hayan sido dados de baja</param>
        /// <returns>Listado de permisos. Listado vacio si no se encuentran</returns>
        /// <exception cref="BusinessException"></exception>
        /// <exception cref="DALException">Error acceso a datos</exception>
        public List<Permiso> Buscar(Usuario usuario, Funcion funcion, bool soloActivos )
        {
            List<Permiso> permisos = new List<Permiso>();
            
            permisos = persistencia.Buscar(usuario, funcion, soloActivos );

            foreach (Permiso permiso in permisos)
            {
                if (permiso.Usuario != null)
                {
                    GestorUsuario gUsuario = new GestorUsuario();
                    permiso.Usuario = gUsuario.CompletarBasico(permiso.Usuario, true);
                }

                if (permiso.Funcion != null)
                {
                    GestorFuncion gFuncion = new GestorFuncion();
                    permiso.Funcion = gFuncion.Completar(permiso.Funcion, true);
                }
            }

            return permisos;
        }

        

        /// <summary>
        /// Obtiene un listado de permisos para un usuario especificio
        /// </summary>
        /// <param name="usuario">Usuario del cual se desean obtener los permisos</param>
        /// <param name="soloActivos">True: Obtiene solo los permisos activos del usuario</param>
        /// <returns>Listado de permisos. Listado vacio si el usuario no tiene permisos</returns>
        /// <exception cref="BusinessException"></exception>
        /// <exception cref="DALException">Error acceso a datos</exception>
        public List<Permiso> CompletarSegunUsuario(Usuario usuario, bool soloActivos)
        {
            if (usuario == null || usuario.Id <= 0) throw new BusinessException("Debe indicar el usuario para completar los permisos");

            List<Permiso> permisos = persistencia.CompletarSegunUsuario(usuario);
            List<Permiso> permisosDevolver = new List<Permiso>();

            foreach (Permiso permiso in permisos)
            {
                if (soloActivos && permiso.FechaBaja > DateTime.MinValue) continue; 
                
                GestorFuncion gFuncion = new GestorFuncion();
                permiso.Funcion = gFuncion.Completar(permiso.Funcion, true);

                permisosDevolver.Add(permiso);
            }

            return permisosDevolver;
        }

        /// <summary>
        /// Obtiene un listado de funciones segun el listado de permisos y
        /// de acuerdo al usuario 
        /// </summary>
        /// <param name="usuario">Usuario del cual se desean obtener las funciones</param>        
        /// <param name="soloActivos">True: Solo incluye los permisos habilitados</param>
        /// <returns>Listado de funciones. Listado vacio si no se encontraron funciones</returns>
        public List<Funcion> CompletarSegunUsuarioSistema(Usuario usuario, bool soloActivos)
        {
            if (usuario == null || usuario.Id <= 0) throw new BusinessException("Debe indicar el usuario para completar los permisos");
            
            List<Permiso> permisos = this.CompletarSegunUsuario(usuario, true);
            List<Funcion> funciones = new List<Funcion>();

            foreach (Permiso permiso in permisos)
            {
                if (permiso.Funcion != null)
                {
                    funciones.Add(permiso.Funcion);
                }
            }

            return funciones;
        }

        /// <summary>
        /// Verifica que un usuario tenga al menos un permiso para un sistema determinado
        /// </summary>
        /// <param name="usuario">Usuario a validar</param>        
        /// <param name="soloActivos">True: Verifica solo los permisos activos</param>
        /// <returns>True: Tiene al menos un permiso activo. False: No tiene permisos activos</returns>
        /// <exception cref="BusinessException">Error de validacion de datos</exception>
        /// <exception cref="DALException">Error acceso a datos</exception>
        public bool PoseePermisosParaSistema(Usuario usuario, bool soloActivos)
        {
            List<Permiso> permisos = CompletarSegunUsuario(usuario, soloActivos);

            foreach(Permiso permiso in permisos)
            {
                if (permiso.Funcion != null)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Verifica que un usuario tenga acceso activo a determinada funcion
        /// </summary>
        /// <param name="usuario">Usuario a validar</param>
        /// <param name="funcion">Funcion a validar</param>
        /// <param name="soloActivos">True: Verifica solo los permisos activos</param>
        /// <returns>True: Tiene acceso. False: no tiene acceso</returns>
        /// <exception cref="BusinessException">Error de validacion de datos</exception>
        /// <exception cref="DALException">Error acceso a datos</exception>
        public bool PoseePermisosParaFuncion(Usuario usuario, Funcion funcion, bool soloActivos)
        {
            List<Permiso> permisos = CompletarSegunUsuario(usuario, soloActivos);

            foreach (Permiso permiso in permisos)
            {
                if (permiso.Funcion != null && permiso.Funcion.Equals(funcion))  return true;
            }

            return false;
        }

        /// <summary>
        /// Verifica que un usuario tenga acceso a determinada funcion
        /// </summary>
        /// <param name="usuario">Usuario a validar</param>        
        /// <param name="codificacionFuncion">Codigo interno de la funcion</param>
        /// <param name="soloActivos">True: Verifica solo los permisos activos</param>
        /// <returns>True: Tiene acceso. False: no tiene acceso</returns>
        /// <exception cref="BusinessException"></exception>
        /// <exception cref="DALException">Error acceso a datos</exception>
        public bool PoseePermisosParaFuncion(Usuario usuario, string codificacionFuncion, bool soloActivos)
        {
            GestorFuncion gFuncion = new GestorFuncion();

            Funcion funcion = gFuncion.CompletarSegunCodigo(codificacionFuncion, soloActivos);

            if (funcion != null && funcion.Id > 0) return PoseePermisosParaFuncion(usuario, funcion, soloActivos);
            return false;
        }

        /// <summary>
        /// Registra un permiso
        /// </summary>
        /// <param name="permiso">Permiso a registrar</param>
        /// <exception cref="BusinessException">Validaciones de negocio</exception>
        /// <exception cref="DALException">Error de acceso a datos</exception>
        public void Registrar(Permiso permiso)
        {
            if (permiso == null) throw new BusinessException("Debe indicar el permiso a registrar");
            if (permiso.FuncionID <= 0) throw new BusinessException("Debe indicar la funcion a registrar");
            if (permiso.UsuarioID <= 0) throw new BusinessException("Debe indicar el usuario a registrar");
            if (permiso.UsuarioAlta == null || permiso.UsuarioAlta.Id <= 0) throw new BusinessException("Debe indicar el usuario que dio de alta el permiso");

            if (this.PoseePermisosParaFuncion(permiso.Usuario, permiso.Funcion, true))
            {
                throw new BusinessException("El usuario ya posee acceso. Funcion: " + permiso.FuncionDescripcion);
            }

            
            permiso.FechaAlta = DateTime.Now;

            //Si el usuario tiene acceso, y el mismo fue deshabilitado, lo activamos
            if (this.PoseePermisosParaFuncion(permiso.Usuario, permiso.Funcion, false))
            {
                this.Activar(permiso);
                return;
            }

            persistencia.Guardar(permiso);
        }

        /// <summary>
        /// Registra un listado de permisos para un usuario
        /// </summary>
        /// <param name="permisos">Listado de permisos a registrar</param>
        /// <exception cref="BusinessException">No se indicaron los datos obligatorios a registrar</exception>
        /// <exception cref="DALException">Error de acceso a datos</exception>
        public void Registrar(List<Permiso> permisos)
        {
            List<Permiso> permisosNuevos = new List<Permiso>();
            
            if (permisos == null || permisos.Count == 0)
                throw new BusinessException("Debe indicar los permisos a registrar");

            foreach (Permiso permiso in permisos) this.Registrar(permiso);
        }

        /// <summary>
        /// Elimina un permiso
        /// </summary>
        /// <param name="permiso">Permiso a eliminar</param>
        /// <exception cref="BusinessException">No se indicaron los datos obligatorios a registrar</exception>
        /// <exception cref="DALException">Error de acceso a datos</exception>
        public void Eliminar(Permiso permiso)
        {
            if (permiso == null) throw new BusinessException("Debe indicar el permiso a registrar");
            if (permiso.FuncionID <= 0) throw new BusinessException("Debe indicar la funcion a registrar");
            if (permiso.UsuarioID <= 0) throw new BusinessException("Debe indicar el usuario a registrar");
            if (permiso.UsuarioBaja == null || permiso.UsuarioBaja.Id <= 0) throw new BusinessException("Debe indicar el usuario que elimina el permiso");

            permiso.FechaBaja = DateTime.Now;

            persistencia.Borrar(permiso);
        }

        /// <summary>
        /// Elimina todos los permisos asociados a un usuario en particular
        /// </summary>
        /// <param name="usuario">Usuario del cual se eliminaran todos los permisos</param>
        /// <param name="usuarioBaja">Usuario que esta dando de baja el permiso</param>        
        /// <exception cref="BusinessException">No se indicaron los datos obligatorios a registrar</exception>
        /// <exception cref="DALException">Error de acceso a datos</exception>
        public void Eliminar(Usuario usuario, Usuario usuarioBaja)
        {
            if (usuario == null || usuario.Id <= 0) throw new BusinessException("Debe indicar el permiso a eliminar");
            if (usuarioBaja == null || usuarioBaja.Id <= 0) throw new BusinessException("Debe indicar el usuario que esta eliminado los permisos");

            List<Permiso> permisosAEliminar = this.Buscar(usuario, null, true );

            foreach (Permiso permiso in permisosAEliminar)
            {
                permiso.UsuarioBaja = usuarioBaja;
                this.Eliminar(permiso);
            }
        }

        /// <summary>
        /// Elimina todos los permisos asociados a una funcion en particular
        /// </summary>
        /// <param name="funcion">Funcion de la cual se eliminaran todos los permisos</param>
        /// <param name="usuarioBaja">Usuario que esta dando de baja el permiso</param> 
        /// <exception cref="BusinessException">No se indicaron los datos obligatorios a registrar</exception>
        /// <exception cref="DALException">Error de acceso a datos</exception>
        public void Eliminar(Funcion funcion, Usuario usuarioBaja)
        {
            if (funcion == null || funcion.Id <= 0) throw new BusinessException("Debe indicar la funcion a eliminar");
            if (usuarioBaja == null || usuarioBaja.Id <= 0) throw new BusinessException("Debe indicar el usuario que esta eliminado los permisos");

            List<Permiso> permisosAEliminar = this.Buscar(null, funcion, true );

            foreach (Permiso permiso in permisosAEliminar)
            {
                permiso.UsuarioBaja = usuarioBaja;
                this.Eliminar(permiso);
            }
        }

        /// <summary>
        /// Reactiva un permiso previamente marcado como eliminado
        /// </summary>
        /// <param name="permiso">Permiso para activar</param>
        /// <exception cref="BusinessException">No se indicaron los datos obligatorios a registrar</exception>
        /// <exception cref="DALException">Error de acceso a datos</exception>
        public void Activar(Permiso permiso)
        {
            if (permiso == null) throw new BusinessException("Debe indicar el permiso a registrar");
            if (permiso.FuncionID <= 0) throw new BusinessException("Debe indicar la funcion a registrar");
            if (permiso.UsuarioID <= 0) throw new BusinessException("Debe indicar el usuario a registrar");

            persistencia.Activar(permiso);
        }

        
    }
}
